/**
 * 
 */
package jvs.peer.vfs;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.security.Principal;
import java.security.acl.Group;
import java.util.ArrayList;
import java.util.List;

import jvs.peer.xmpp.XmppPeerPrincipal;
import jvs.vfs.IFileBaseImpl;
import jvs.vfs.sec.AccessControl;
import jvs.vfs.sec.User;
import x.java.io.File;

/**
 * @author qiangli
 * 
 */
public class GroupFileImpl extends IFileBaseImpl {
	public class PeerOutputStream extends ByteArrayOutputStream {
		public PeerOutputStream() {
		}

		@Override
		public void close() throws IOException {
			AccessControl acl = getAccessControl();
			if (acl != null && peer != null && group != null) {
				String s = new String(toByteArray());
				String[] sa = s.split("[\r\n]+");
				for (int i=0; i<sa.length; i++) {
					if (sa[i].startsWith("name:")) {
						acl.updateUser(peer, sa[i].substring(5).trim());
					}
				}
			}
		}
	}

	private static final String SCHEME = "group";

	private String group;

	private String peer;


	/**
	 * @param uri
	 */
	public GroupFileImpl(URI uri) {
		super(uri);
		
		// group:/group/peer
		if (uri.getScheme() == null
				|| !uri.getScheme().equalsIgnoreCase(SCHEME)) {
			throw new IllegalArgumentException("incorrect scheme: "
					+ uri.getScheme());
		}
		String path = uri.toString();
		path = path.substring(6).trim();
		int len = path.length();
		if (len == 0 || path.charAt(0) != '/') {
			throw new IllegalArgumentException("path not absolute: " + path);
		}
		// path = /
		if (len == 1) {
			return;
		}
		if (path.charAt(len-1) == '/') {
			path = path.substring(0,len - 1);
		}
		int idx = path.indexOf('/', 1);
		if (idx == -1) {
			group = path.substring(1);
			peer = null;
			return;
		}
		// idx > 1
		group = path.substring(1, idx);
		peer = path.substring(idx + 1);
	}
	
	protected GroupFileImpl() {
	}

	protected GroupFileImpl(String group, String peer) {
		this.group = group;
		this.peer = peer;
	}

	@Override
	public boolean canRead() {
		return exists();
	}

	@Override
	public boolean canWrite() {
		return exists();
	}

	/**
	 * add peer to group
	 */
	@Override
	public boolean create() {
		if (peer == null) {
			return false;
		}
		AccessControl acl = getAccessControl();
		if (acl ==  null) {
			return false;
		}
		return acl.addPrincipal(peer, peer, group);
	}

	/**
	 * delete group if empty or peer from group
	 */
	@Override
	public boolean delete() {
		if (peer == null && group == null) {
			return false; // peer root /
		}
		// remove group if no peers
		AccessControl acl = getAccessControl();
		if (acl ==  null) {
			return false;
		}
		if (peer == null) {
			if (acl.getPrincipals(group) == null) {
				acl.removeGroup(group);
				return true;
			}
			return false;
		}
		// remove peer from group
		return acl.removePrincipal(peer, group);
	}

	@Override
	public boolean exists() {
		//root always exists
		if (peer == null && group == null) {
			return true;
		}
		// group
		AccessControl acl = getAccessControl();
		if (acl ==  null) {
			return false;
		}
		if (peer == null) {
			return acl.checkGroup(group);
		}
		return acl.checkGroup(peer, group);
	}

	@Override
	public String getContentType() {
		if (peer == null && group == null) {
			return "application/folder";
		}
		if (peer == null && group != null) {
			return "application/peer-group";
		}
		return "application/peer";
	}

	@Override
	public String getDisplayName() {
		//TODO
		return super.getDisplayName();
	}

	@Override
	public InputStream getInputStream() {
		AccessControl acl = getAccessControl();
		if (acl ==  null) {
			return null;
		}
		if (peer == null || group == null) {
			return null;
		}
		try {
			User u = acl.findUser(peer);
			StringBuilder sb = new StringBuilder();
			sb.append("id: ");
			sb.append(u.getId());
			sb.append(File.CRLF);
			sb.append("name: ");
			sb.append(u.getName());
			sb.append(File.CRLF);
			return new ByteArrayInputStream(sb.toString().getBytes());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public OutputStream getOutputStream() {
		AccessControl acl = getAccessControl();
		if (acl ==  null) {
			return null;
		}
		if (peer == null || group == null) {
			return null;
		}
		return new PeerOutputStream();
	}

	/**
	 * group is directory
	 * @return true if and only if the file denoted by this abstract pathname exists and is a directory; false otherwise
	 */
	@Override
	public boolean isDirectory() {
		if (peer != null) {
			return false;
		}
		AccessControl acl = getAccessControl();
		if (acl == null) {
			return false;
		}
		return acl.checkGroup(group);
	}

	/**
	 *
	 */
	@Override
	public boolean isEmpty() {
		//isDirecotry && list().length == 0
		if (peer != null) {
			return false;
		}
		AccessControl acl = getAccessControl();
		if (acl ==  null) {
			return true; //
		}
		if (peer == null && group == null) {
			//root
			return false;
		} else {
			//peers in group
			return acl.getPrincipals(group).size() > 0;
		}
	}

	/**
	 * Peer is file
	 * @return true if and only if the file denoted by this abstract pathname exists and is a normal file; false otherwise 
	 */
	@Override
	public boolean isFile() {
		if (peer == null){
			return false;
		}
		AccessControl acl = getAccessControl();
		if (acl == null) {
			return false;
		}
		return acl.checkGroup(peer, group);
	}

	@Override
	public String[] list() {
		if (peer != null) {
			return null;
		}
		List<String> l = new ArrayList<String>();
		AccessControl acl = getAccessControl();
		if (acl ==  null) {
			return null; //
		}
		if (peer == null && group == null) {
			//root
			for (Group g : acl.groups()) {
				l.add(g.getName());
			}
		} else {
			//peers in group
			for (Principal p : acl.getPrincipals(group)) {
				l.add(((XmppPeerPrincipal) p).getId());
			}
		}
		return l.toArray(new String[0]);
	}

	@Override
	public boolean isLocal() {
		return true; //TODO
	}

	@Override
	public boolean isNative() {
		return false;
	}

	@Override
	public boolean mkdir() {
		if (peer != null) {
			return false;
		}
		AccessControl acl = getAccessControl();
		if (acl ==  null) {
			return false;
		}
		return acl.addGroup(group);
	}

	@Override
	public boolean move(URI uri) {
		if (uri.getScheme() == null
				|| !uri.getScheme().equalsIgnoreCase("group")) {
			throw new IllegalArgumentException("incorrect scheme: "
					+ uri.getScheme());
		}
		// TODO
		return false;
	}

	@Override
	public String getName() {
		if (group == null) {
			return "";
		}
		//group
		if (peer == null) {
			return group;
		}
		//peer
		return peer;
	}

	@Override
	protected String getParent() {
		if (group == null) {
			return null;
		}
		//group
		if (peer == null) {
			return "/";
		}
		//peer
		return "/"+group;
	}

	private String relpath() {
		String p = (group == null ? "" : group);
		p = (peer == null ? p : p + "/" + peer);
		return p;
	}

	@Override
	public URI toRealURI() {
		return URI.create(SCHEME+":/"+relpath());
	}

	@Override
	public String toString() {
		return SCHEME+":/"+relpath();
	}
}
